package com.lxb.myforum.service

import java.util.*

import com.lxb.myforum.base.BaseService
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.data.domain.Page
import org.springframework.data.domain.PageRequest
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate
import org.springframework.stereotype.Service

import com.lxb.myforum.pojo.Authority
import com.lxb.myforum.pojo.Resource
import com.lxb.myforum.repository.AuthorityRepository
import com.lxb.myforum.repository.ResourceRepository

/**
 * @author lxb
 */
@Service
class AuthorityService @Autowired
constructor(
        private val authorityRepository: AuthorityRepository,
        private val resourceRepository: ResourceRepository,
        private val namedParameterJdbcTemplate: NamedParameterJdbcTemplate
) : BaseService() {

    /**
     * 获取权限信息【分页】
     *
     * @param rp
     * @return
     */
    fun getAuthorities(rp: PageRequest): Page<Authority> {
        return authorityRepository.findAll(rp)
    }

    /**
     * 新增或者更新数据
     *
     * @param authority 要保存的Authority
     * @return { "action": "", result: "", object: "" }
     */
    fun saveAuth(authority: Authority?): Map<String, Any> {
        val result = HashMap<String, Any>()

        if (null == authority) {
            result["action"] = "滚蛋"
            result["result"] = 0
            return result
        }
        if (authority.id!! > 0) { // id 存在，说明是更新操作
            result["action"] = "update"
        } else { // id 不存在
            result["action"] = "insert"
        }
        val r = authorityRepository.save(authority)
        if (r.id!! > 0) {
            result["result"] = 1 // 成功
        } else {
            result["result"] = -1 // 失败
        }
        result["object"] = r

        return result
    }

    /**
     * 根据id 删除对应的Authority
     *
     * @param id
     * @return
     */
    fun deleteAuthById(id: Long): Map<String, Any> {
        val result = HashMap<String, Any>()
        result["action"] = "delete"

        // 只会删除该id的Resource和与该Resource相关的联系（如果是多对多，即是第三张表的数据【两者之间的联系】）
        // 并不会删除与该Resource相关连的表的信息
        try {
            authorityRepository.deleteById(id)
            result["result"] = 1
        } catch (e: IllegalArgumentException) {
            result["result"] = -1
        }

        return result
    }

    fun findOwnRes(authId: Long): List<Resource> {
        return authorityRepository.findById(authId)
                .map<List<Resource>> { it.resources }
                .orElse(null)
    }

    /**
     * 获取不属于该权限的资源
     *
     * @param authId
     * @return
     */
    fun findNotOwnRes(authId: Long): List<Resource> {
        return resourceRepository.findNotAuthRes(authId)
    }

    fun addAuthRes(authId: Long, resIds: Set<Long>): MutableMap<String, Any> {
        val result = HashMap<String, Any>()
        val insertSql = "insert into t_authority_resource(resource_id, authority_id) values(:resId, :authId)"
        try {
            val batchValues = makeMapSqlParameterSource(authId, resIds)
            namedParameterJdbcTemplate.batchUpdate(insertSql, batchValues)

            result["result"] = 1
            result["msg"] = "添加成功"
        } catch (e: Exception) {
            result["result"] = -1
            result["msg"] = "添加失败"
        }

        return result
    }

    fun delAuthRes(authId: Long, resIds: Set<Long>): MutableMap<String, Any> {
        val result = HashMap<String, Any>()
        val delSql = "delete from t_authority_resource where resource_id = :resId and authority_id = :authId"
        try {
            val batchValues = makeMapSqlParameterSource(authId, resIds)
            namedParameterJdbcTemplate.batchUpdate(delSql, batchValues)

            result["result"] = 1
            result["msg"] = "删除成功"
        } catch (e: Exception) {
            result["result"] = -1
            result["msg"] = "删除失败"
        }

        return result
    }

    private fun makeMapSqlParameterSource(authId: Long, resIds: Set<Long>): Array<MapSqlParameterSource> {
        return resIds.stream()
                .map { resId ->
                    val mapSqlParameterSource = MapSqlParameterSource("resId", resId)
                    mapSqlParameterSource.addValue("authId", authId)
                    mapSqlParameterSource
                }
                .toArray { arrayOfNulls<MapSqlParameterSource>(it) }
    }
}
